import 'package:analyzer/dart/element/element.dart' as ele;
import 'package:source_gen/source_gen.dart';
import 'package:build/build.dart';
import 'package:dart_style/dart_style.dart';
import 'package:xanno/src/anno/entity/generator.dart';
import 'package:xanno/src/anno/utils/log.dart';
import 'dart:io';
import 'formatter.dart';

class FormatterGenerator extends GeneratorForAnnotation<GFormatter> {
  final separator = Platform.pathSeparator;
  List<String> files = [];
  List result = [];
  List ignores = [
    '.entity.dart',
    '.route.dart',
    '.assets.dart',
    '.api.dart',
    '.iconfont.dart',
    '.interface.dart',
    '.formatter.dart',
    '.color.dart',
    '.size.dart',
    '.jenkinsfile.dart',
  ];
  int totalCodeLines = 0;
  int removeEmptyLinesCodeLines = 0;

  void queryFiles(String root, List<String> list) {
    try {
      var directory = Directory(root);
      List<FileSystemEntity> files = directory.listSync();
      files.forEach((f) {
        var bool = FileSystemEntity.isFileSync(f.path);
        if (!bool) {
          queryFiles(f.path, list);
        } else {
          ///之后可以通过文件hash 来判断文件是否被变化，格式化代码效率
          ///忽略自动生成代码
          var ignoreItem;
          try {
            ignoreItem =
                ignores.firstWhere((element) => f.path.endsWith(element));
          } catch (e) {}
          if (ignoreItem == null && f.path.endsWith('.dart')) {
            list.add(f.path);
          }
        }
      });
    } catch (e) {
      logPrint("目录不存在!$root", level: Level.error);
    }
  }

  void queryFileLines(String root) {
    try {
      var directory = Directory(root);
      List<FileSystemEntity> files = directory.listSync();
      files.forEach((f) {
        var bool = FileSystemEntity.isFileSync(f.path);
        if (!bool) {
          queryFileLines(f.path);
        } else {
          // 只统计dart文件
          if (f.path.endsWith('.dart')) {
            final rsc = File(f.path).readAsLinesSync();
            rsc.forEach((element) {
              if (element.isNotEmpty && element.length > 0) {
                removeEmptyLinesCodeLines += 1;
              }
            });
            totalCodeLines += rsc.length;
          }
        }
      });
    } catch (e) {
      logPrint("目录不存在!$root", level: Level.error);
    }
  }

  String? formatCode(codeStr) {
    var formatter = DartFormatter();
    String? codeF;
    try {
      codeF = formatter.format(codeStr);
    } on FormatterException catch (ex) {
      logPrint(ex, level: Level.error);
    }
    return codeF;
  }

  formatFile(path, List<String> ignoresDirs, List<String> ignoresFiles) async {
    ///使用同一个file操作
    File file = File(path);
    try {
      ///先格式化代码
      String codeStr = await file.readAsString();
      String? codeF = formatCode(codeStr);
      if (codeF == null) {
        return null;
      }

      ///写入文件
      file = await file.writeAsString(codeF);

      ///再统计代码行数
      int lines = (await file.readAsLines()).length;

      /// 过滤忽略
      var name = path.split("${separator}lib$separator").last;
      var igDir = false;
      for (var item in ignoresDirs) {
        if (name.contains(item)) {
          igDir = true;
          break;
        }
      }
      var igFile = ignoresFiles.indexOf(name) >= 0;
      if (!igDir && !igFile) {
        result.add({'path': path, 'lines': lines});
      }
    } catch (e) {
      logPrint('读取文件失败! $path $e', level: Level.error);
    }
  }

  void printResult(int maxLine) {
    int lengthW = 80;
    StringBuffer sb = StringBuffer();
    for (int i = 0; i < lengthW; i++) {
      if (i == 0) sb.write('╔');
      sb.write('═');
    }
    // 过滤model生成文件
    if (EntityGenerator.entityMapPath.isNotEmpty) {
      try {
        result = result.where((element) {
          String path = element["path"];
          String endSub = path.split('lib$separator').last;
          Map mapTmp = EntityGenerator.entityMapPath.map(
              (key, value) => MapEntry(key.split('lib$separator').last, value));
          return !mapTmp.containsKey(endSub);
        }).toList();
      } catch (e) {}
    }
    sb.write('\n║ 需优化代码行数的文件如下: [line >= $maxLine]');
    int index = 0;
    result.forEach((item) {
      var lines = item['lines'];
      if (lines >= maxLine) {
        index++;
        sb.write('\n║ [$index]\t[line:$lines]\t${item['path']}\t');
      }
    });
    for (int i = 0; i < lengthW; i++) {
      if (i == 0) sb.write('\n╚');
      sb.write('═');
    }
    if (index > 0) {
      logPrint(sb.toString(), level: Level.def);
    }
  }

  void printLine(String text) {
    int lengthW = 80;
    StringBuffer sb = StringBuffer();
    for (int i = 0; i < lengthW; i++) {
      if (i == 0) sb.write('╔');
      sb.write('═');
    }
    sb.write('\n║ $text');
    for (int i = 0; i < lengthW; i++) {
      if (i == 0) sb.write('\n╚');
      sb.write('═');
    }
    logPrint(sb.toString(), level: Level.info);
  }

  @override
  generateForAnnotatedElement(ele.Element element, ConstantReader annotation,
      BuildStep buildStep) async {
    // logPrint('start formatter', level: Level.info);
    int maxLine = 0;
    var enable = false;
    List<String> ignoresFiles = [];
    List<String> ignoresDirs = [];
    var showTotalCodeLines = false;
    try {
      enable = annotation.read('enable').boolValue;
    } catch (e) {}
    if (!enable) return null;
    try {
      maxLine = annotation.read('maxLine').intValue;
    } catch (e) {}
    try {
      ignoresFiles = annotation
          .read('ignoresFiles')
          .listValue
          .map((e) => e.toStringValue()!)
          .toList();
    } catch (e) {}
    try {
      ignoresDirs = annotation
          .read('ignoresDirs')
          .listValue
          .map((e) => e.toStringValue()!)
          .toList();
    } catch (e) {}
    try {
      showTotalCodeLines = annotation.read('showTotalCodeLines').boolValue;
    } catch (e) {}
    String root = '${Directory.current.path}${separator}lib';
    queryFiles(root, files);
    await Future.wait(files
        .map((path) async => await formatFile(path, ignoresDirs, ignoresFiles))
        .toList());
    if (result.length > 0) {
      printResult(maxLine);
    }
    if (showTotalCodeLines) {
      queryFileLines(root);
      printLine(
          "lib目录下包含空行源码行数:$totalCodeLines  除去空行源码行数:$removeEmptyLinesCodeLines");
    }
    return null;
  }
}

Builder formatterBuilder(BuilderOptions options) =>
    LibraryBuilder(FormatterGenerator(), generatedExtension: ".formatter.dart");
